package com.xh.bussiness.tiku.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xh.bussiness.tiku.bean.dto.KnowledgeDto;
import com.xh.bussiness.tiku.bean.request.KnowledgeRequest;
import com.xh.bussiness.tiku.bean.request.SaveKnowledgeRequest;
import com.xh.bussiness.tiku.model.Knowledge;
import com.xh.bussiness.tiku.dao.KnowledgeMapper;
import com.xh.bussiness.tiku.model.QuestionKnowledge;
import com.xh.bussiness.tiku.service.IBookChapterService;
import com.xh.bussiness.tiku.service.IKnowledgeService;
import com.xh.bussiness.tiku.service.IQuestionKnowledgeService;
import com.xh.core.exception.XhException;
import com.xh.core.service.impl.BaseServiceImpl;
import com.xh.core.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.xh.core.bean.XhPage;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 知识点信息表 服务实现类
 * </p>
 *
 * @author daiwei
 * @since 2019-01-14
 */
@Service
public class KnowledgeServiceImpl extends BaseServiceImpl<KnowledgeMapper, Knowledge> implements IKnowledgeService {
    public static final Logger log = LoggerFactory.getLogger(KnowledgeServiceImpl.class);

    @Autowired
    private IQuestionKnowledgeService questionKnowledgeService;
    @Autowired
    private IBookChapterService bookChapterService;

    @Override
    public XhPage queryKnowledgePage(XhPage page, KnowledgeRequest bean) {
        QueryWrapper qw = new QueryWrapper<Knowledge>();
        // 拼装条件
        qw = prepareParams(bean, qw);

        return (XhPage) this.selectPage(page, qw, KnowledgeDto.class);
    }

    @Override
    public List queryKnowledge(KnowledgeRequest bean) {
        QueryWrapper qw = new QueryWrapper<Knowledge>();
        // 拼装条件
        qw = prepareParams(bean, qw);

        return this.dao.selectList(qw);
    }

    /**
     * 准备条件
     *
     * @param bean
     * @param qw
     */
    private QueryWrapper prepareParams(KnowledgeRequest bean, QueryWrapper<Knowledge> qw) {
        if (bean.getIds() != null && bean.getIds().length > 0) {
            qw.in("id", bean.getIds());
        }
        if (!StringUtils.isEmpty(bean.getSubjectId())) {
            qw.eq("subject", bean.getSubjectId());
        }
        if (!StringUtils.isEmpty(bean.getGradeRange())) {
            qw.eq("grade_range", bean.getGradeRange());
        }
        if (!StringUtils.isEmpty(bean.getParentId())) {
            if (bean.getParentId().equals("0")) {
              qw.isNull("parent_id");
//                qw.and(wrapper -> wrapper.isNull("parent_id").or().eq("parent_id",""));
            } else {
                qw.eq("parent_id", bean.getParentId());
            }
        }
        if (!StringUtils.isEmpty(bean.getName())) {
            qw.like("name", bean.getName());
        }
        if (!StringUtils.isEmpty(bean.getParentPath())) {
            qw.eq("parent_path", bean.getParentPath());
        }
        if (!StringUtils.isEmpty(bean.getParentPathName())) {
            qw.eq("parent_path_name", bean.getParentPathName());
        }
        qw.orderByAsc("sort_index");
        return qw;
    }

    @Override
    public List<KnowledgeDto> queryTree(KnowledgeRequest bean) {
        QueryWrapper qw = new QueryWrapper<Knowledge>();
        // 拼装条件
        qw = prepareParams(bean, qw);
        List<KnowledgeDto> list = this.selectList(qw, KnowledgeDto.class);
        List<KnowledgeDto> roots = getRoots(list);
        findChilds(roots, list);

        return roots;
    }

    /**
     * 获取父节点
     *
     * @param list
     * @return
     */
    public List<KnowledgeDto> getRoots(List<KnowledgeDto> list) {
        List<KnowledgeDto> roots = new ArrayList<KnowledgeDto>();
        for (KnowledgeDto knowledgeDto : list) {
            if ("0".equals(knowledgeDto.getParentId()) || StringUtils.isEmpty(knowledgeDto.getParentId())) {
                roots.add(knowledgeDto);
            }
        }
        return roots;
    }

    /**
     * 获取子节点
     *
     * @param roots
     * @param list
     */
    public void findChilds(List<KnowledgeDto> roots, List<KnowledgeDto> list) {
        for (KnowledgeDto parent : roots) {
            List<KnowledgeDto> childs = new ArrayList<KnowledgeDto>();
            for (KnowledgeDto child : list) {
                if (child.getParentId() != null && child.getParentId().equals(parent.getId())) {
                    childs.add(child);
                }
            }
            parent.setChilds(childs);
            findChilds(childs, list);
        }
    }

    @Override
    public void truncateTable() {
        this.dao.truncateTable();

    }

    @Override
    public void initKnowledgeSortIndex(String subject) {
        QueryWrapper<Knowledge> qw = new QueryWrapper<>();
        qw.eq("subject", subject);
        qw.orderByAsc("no");
        qw.isNull("parent_id");

        List<Knowledge> roots = this.dao.selectList(qw);
        for (int i = 0; i < roots.size(); i++) {
            Knowledge knowledge = roots.get(i);

            getChild(knowledge.getId());

            knowledge.setSortIndex((i + 1));
            this.dao.updateById(knowledge);
        }
    }

    /**
     * 获取当前节点上面或下面的一个节点
     *
     * @param subjectCode
     * @param parentId
     * @param sortIndex
     * @param moveType
     * @return
     */
    private Knowledge getUpOrDownKnowledge(String subjectCode, String parentId, Integer sortIndex, Integer moveType) {
        QueryWrapper<Knowledge> qw = new QueryWrapper<>();
        qw.eq("subject", subjectCode);
        if (StringUtils.isEmpty(parentId)) {
            qw.isNull("parent_id");
        } else {
            qw.eq("parent_id", parentId);
        }
        if (moveType.equals(1)) {
            //上移
            qw.lt("sort_index", sortIndex);
            qw.orderByDesc("sort_index");
        } else {
            qw.gt("sort_index", sortIndex);
            qw.orderByAsc("sort_index");
        }
        return this.selectFirst(qw);
    }


    List<Knowledge> getChild(String parentId) {
        QueryWrapper<Knowledge> qw = new QueryWrapper<>();
        qw.eq("parent_id", parentId);
        List<Knowledge> childs = this.dao.selectList(qw);
        if (!CollectionUtils.isEmpty(childs)) {
            for (int i = 0; i < childs.size(); i++) {
                Knowledge knowledge = childs.get(i);
                knowledge.setSortIndex((i + 1));
                this.dao.updateById(knowledge);

                getChild(knowledge.getId());
            }
        }
        return new ArrayList<>();
    }


    @Override
    public List<Knowledge> queryKnowledgeByChapterId(String chapterId, String chapterName) {
        List<Knowledge> knowledges = this.dao.queryKnowledgeByChapterId(chapterId);
        knowledges.stream().forEach(item -> {
            item.setChapterId(chapterId);
            item.setChapterName(chapterName);
        });
        return knowledges;
    }

    @Override
    public boolean addKnowledge(SaveKnowledgeRequest request) {
        Integer orderNo = this.dao.getMaxSortIndexKnowledgeBySubjectCode(request.getSubject(), request.getParentId());
        orderNo = orderNo == null ? 1 : orderNo + 1;

        Knowledge knowledge = new Knowledge();
        if(StringUtils.isNotEmpty(request.getId())){
            knowledge.setId(request.getId());
        }
        knowledge.setName(request.getKnowledgeName());
        knowledge.setSubject(request.getSubject());
        knowledge.setSortIndex(orderNo);

        boolean insert = this.insert(knowledge);
        if (!insert) {
            throw new XhException("has error");
        }

        if (!StringUtils.isEmpty(request.getParentId())) {
            Knowledge parent = this.getById(request.getParentId());
            if (parent == null) {
                throw new XhException(String.format("addKnowledge parent not find by parentId:%s", request.getParentId()));
            }
            knowledge.setParentId(request.getParentId());
            knowledge.setParentPath(request.getParentPath());
            knowledge.setParentPathName(request.getParentPathName());
            knowledge.setPath(String.format("%s%s-", parent.getPath(), knowledge.getId()));
            knowledge.setPathName(String.format("%s%s-", parent.getPathName(), parent.getName()));
        } else {
            knowledge.setPath(String.format("-%s-", knowledge.getId()));
            knowledge.setPathName(String.format("-%s-", knowledge.getName()));
        }
        this.dao.updateById(knowledge);
        bookChapterService.deleteCacheBySubjectCode(knowledge.getSubject());
        return true;
    }

    @Override
    public boolean batchInsertKnowledge(List<KnowledgeRequest> requests) {
        for (KnowledgeRequest request : requests) {
            Integer orderNo = this.dao.getMaxSortIndexKnowledgeBySubjectCode(request.getSubjectId(), request.getParentId());
            orderNo = orderNo == null ? 1 : orderNo + 1;
            Knowledge knowledge = new Knowledge();
//            knowledge.setId(request.getId());
            knowledge.setName(request.getName());
            knowledge.setSubject(request.getSubjectId());
            knowledge.setSortIndex(orderNo);
            boolean insert = this.insert(knowledge);
            if (insert) {
                knowledge.setPath(String.format("-%s-", knowledge.getId()));
                knowledge.setPathName(String.format("-%s-", knowledge.getName()));
                this.dao.updateById(knowledge);
            }
            if (request.getChilds() != null && request.getChilds().size() > 0) {
                batchInsertChildKnowledge(request.getChilds(), request.getSubjectId(),knowledge);
            }
        }
        return true;
    }

    private void batchInsertChildKnowledge(List<KnowledgeDto> childs, String subjectId,Knowledge knowledge) {
        for (KnowledgeDto knowledgeDto : childs) {
            Integer orderNo = this.dao.getMaxSortIndexKnowledgeBySubjectCode(subjectId, knowledgeDto.getParentId());
            orderNo = orderNo == null ? 1 : orderNo + 1;
            Knowledge knowledge1 = new Knowledge();
            knowledge1.setName(knowledgeDto.getName());
            knowledge1.setSubject(subjectId);
            knowledge1.setSortIndex(orderNo);
            boolean insert = this.insert(knowledge1);
            if (insert && !StringUtils.isEmpty(knowledge.getId())) {
                Knowledge parent = this.getById(knowledge.getId());
                if (parent == null) {
                    throw new XhException(String.format("addKnowledge parent not find by parentId:%s", knowledge.getId()));
                }
                knowledge1.setParentId(parent.getId());
                knowledge1.setParentPath(parent.getPath());
                knowledge1.setParentPathName(parent.getPathName());
                knowledge1.setPath(String.format("%s%s-", parent.getPath(), knowledge1.getId()));
                knowledge1.setPathName(String.format("%s%s-", parent.getPathName(), parent.getName()));
                this.dao.updateById(knowledge1);
            }
            if (knowledgeDto.getChilds() != null && knowledgeDto.getChilds().size() > 0) {
                batchInsertChildKnowledge(knowledgeDto.getChilds(),subjectId,knowledge1);
            }
        }
    }

    @Override
    public boolean delete(Serializable id) {
        Knowledge knowledge = this.getById(id);
        if (knowledge != null) {
            bookChapterService.deleteCacheBySubjectCode(knowledge.getSubject());
        }

        boolean result = super.delete(id);
        QueryWrapper<QuestionKnowledge> qw = new QueryWrapper<>();
        qw.eq("knowledge_id", id);
        questionKnowledgeService.deleteByCondition(qw);
        return result;
    }

    @Override
    public boolean batchDelete(Serializable[] ids) {
        if (ids != null && ids.length > 0) {
            Knowledge knowledge = this.getById(ids[0]);
            if (knowledge != null) {
                bookChapterService.deleteCacheBySubjectCode(knowledge.getSubject());
            }
        }
        boolean result = super.batchDelete(ids);
        QueryWrapper<QuestionKnowledge> qw = new QueryWrapper<>();
        qw.in("knowledge_id", ids);
        questionKnowledgeService.deleteByCondition(qw);
        return result;
    }

    /**
     * 上移下移
     *
     * @param knowledgeId
     * @param moveType
     * @return boolean
     * @author 赵文博
     * @date 2021/4/13 16:41
     **/
    @Override
    public boolean moveUpOrDownBookKnowledge(String knowledgeId, Integer moveType) {
        if (StringUtils.isEmpty(knowledgeId) || moveType == null) {
            log.error("moveUpOrDownBookKnowledge params error");
            return false;
        }
        Knowledge knowledge = this.getById(knowledgeId);
        if (knowledge == null) {
            log.error(String.format("moveUpOrDownBookKnowledge current node is null by id:%s", knowledgeId));
            return false;
        }
        //相邻节点
        Knowledge siblingsNode = getUpOrDownKnowledge(knowledge.getSubject(), knowledge.getParentId(), knowledge.getSortIndex(), moveType);
        if (siblingsNode != null) {
            Integer oldSortIndex = knowledge.getSortIndex();
            knowledge.setSortIndex(siblingsNode.getSortIndex());
            siblingsNode.setSortIndex(oldSortIndex);
            //交换排序
            this.update(knowledge);
            this.update(siblingsNode);
        }

        bookChapterService.deleteCacheBySubjectCode(knowledge.getSubject());
        return true;
    }

    /**
     * 拖拽移动
     *
     * @param requests
     * @return void
     * @author 赵文博
     * @date 2021/4/13 16:41
     **/
    @Override
    @Transactional
    public void moveUpOrDownBookKnowledge(List<KnowledgeRequest> requests) {
        for (int i = 0; i < requests.size(); i++) {
            KnowledgeRequest request = requests.get(i);
            Knowledge knowledge = new Knowledge();
            knowledge.setId(request.getId());
            knowledge.setParentId(request.getParentId()==null ?"0":request.getParentId());
            knowledge.setParentPath(request.getParentPath());
            knowledge.setParentPathName(request.getParentPathName());
            knowledge.setPath(request.getPath());
            knowledge.setPathName(request.getPathName());
            knowledge.setSortIndex(i + 1);
            this.update(knowledge);
        }
    }

    @Override
    public boolean addKnowledg2(SaveKnowledgeRequest request) {
        Integer orderNo = this.dao.getMaxSortIndexKnowledgeBySubjectCode(request.getSubject(), request.getParentId());
        orderNo = orderNo == null ? 1 : orderNo + 1;

        Knowledge knowledge = new Knowledge();
        knowledge.setId(request.getId());
        knowledge.setName(request.getKnowledgeName());
        knowledge.setSubject(request.getSubject());
        knowledge.setSortIndex(orderNo);

        boolean insert = this.insert(knowledge);
        if (!insert) {
            throw new XhException("has error");
        }
        if (!StringUtils.isEmpty(request.getParentId())) {
            Knowledge parent = this.getById(request.getParentId());
            if (parent == null) {
                throw new XhException(String.format("addKnowledge parent not find by parentId:%s", request.getParentId()));
            }
            knowledge.setParentId(request.getParentId());
            knowledge.setParentPath(request.getParentPath());
            knowledge.setParentPathName(request.getParentPathName());
            knowledge.setPath(String.format("%s%s-", parent.getPath(), knowledge.getId()));
            knowledge.setPathName(String.format("%s%s-", parent.getPathName(), parent.getName()));
        } else {
            knowledge.setPath(String.format("-%s-", knowledge.getId()));
            knowledge.setPathName(String.format("-%s-", knowledge.getName()));
        }
        this.dao.updateById(knowledge);
        return true;
    }
}
